package cn.xunjie.ymcc.service.impl;

import cn.xunjie.ymcc.domain.AlipayInfo;
import cn.xunjie.ymcc.domain.PayOrder;
import cn.xunjie.ymcc.dto.AlipayNotifyDto;
import cn.xunjie.ymcc.dto.PayApplyDto;
import cn.xunjie.ymcc.dto.PayDto;
import cn.xunjie.ymcc.dto.PayNotifyDto;
import cn.xunjie.ymcc.exception.GlobalException;
import cn.xunjie.ymcc.mapper.PayOrderMapper;
import cn.xunjie.ymcc.service.IAlipayInfoService;
import cn.xunjie.ymcc.service.IPayOrderService;
import cn.xunjie.ymcc.util.AssertUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.common.models.AlipayTradeCloseResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.page.Client;
import com.alipay.easysdk.kernel.Config;

import java.util.Date;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xue.jiao
 * @since 2022-07-31
 */
@Service
@Slf4j
public class PayOrderServiceImpl extends ServiceImpl<PayOrderMapper, PayOrder> implements IPayOrderService {
    @Autowired
    private IAlipayInfoService alipayInfoService;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Override
    public PayOrder selectOrderNo(String orderNo) {

        Wrapper<PayOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no", orderNo);
        return selectOne(wrapper);
    }

    @Override
    public String apply(PayApplyDto dto) {
        PayOrder payOrder = selectOrderNo(dto.getOrderNo());
        AssertUtil.isNotNull(payOrder,"支付单不能为空");
        boolean b = payOrder.getPayStatus() == PayOrder.STAE_WAIT_PAY;
        AssertUtil.isTrue(b,"支付单状态异常，发起支付失败");
        if(payOrder.getPayType() == 1 ){
            return alipay(payOrder,dto);
        }
        return null;
    }

    @Override
    public String notify(AlipayNotifyDto dto) throws Exception {

        String jsonString = JSON.toJSONString(dto);
        Map<String, String> map = JSONObject.parseObject(jsonString, Map.class);
        Boolean notify = Factory.Payment.Common().verifyNotify(map);
        if (!notify) {
            return "Fail";
        }
        PayOrder payOrder = selectOrderNo(dto.getOut_trade_no());
        if (payOrder == null) {
            return "Fail";
        }

        if (payOrder.getPayStatus() == PayOrder.STAE_CANCEL) {
            try {
                AlipayTradeRefundResponse refund = Factory.Payment.Common().refund(payOrder.getOrderNo(), payOrder.getAmount().toString());
            } catch (Exception e) {
                e.printStackTrace();
                //补偿
            }
            return "success";
        }


        if (payOrder.getPayStatus() != PayOrder.STAE_WAIT_PAY) {
            return "Fail";
        }
        String trade_status = dto.getTrade_status();
        if (!trade_status.equals(AlipayNotifyDto.TRADE_SUCCESS)) {
            return "Fail";
        }
        //修改支付单状态
        payOrder.setPayStatus(PayOrder.STAE_PAY_SUCCESS);
        payOrder.setUpdateTime(new Date());
        //updateById(payOrder);事务监听器中改
        PayNotifyDto payNotifyDto = new PayNotifyDto(payOrder.getOrderNo(),payOrder.getExtParams());
        log.info("发布成功事务消息");
        Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(payNotifyDto)).build();
        TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction(
                "service-pay-tx-group",
                "pay-notify-topic:pay-notify-tag",
                message,  //消息体
                payOrder
        );
        log.info("发送完事务消息--检查事务消息状态");
        LocalTransactionState localTransactionState = transactionSendResult.getLocalTransactionState();
        SendStatus sendStatus = transactionSendResult.getSendStatus();
        if(localTransactionState != LocalTransactionState.COMMIT_MESSAGE || sendStatus != SendStatus.SEND_OK ){
            log.info("校验发送事务消息状态异常");
            throw new GlobalException("下单失败！！");
        }



        return "success";


    }

    @Override
    public void cancelOrder(String orderNo) {
        PayOrder payOrder = selectOrderNo(orderNo);
        //取消支付单
        if(payOrder.getPayStatus().intValue() == PayOrder.STAE_WAIT_PAY){
            payOrder.setPayStatus(PayOrder.STAE_CANCEL);
        }
        try {
            AlipayTradeCloseResponse close = Factory.Payment.Common().close(orderNo);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public String alipay(PayOrder payOrder,PayApplyDto dto){
        AlipayInfo info = alipayInfoService.selectOne(null);
        // 1. 设置参数（全局只需设置一次）
        Factory.setOptions(getOptions(info));
        try {
            // 2. 网页端支付
            Client page = Factory.Payment.Page();
            AlipayTradePagePayResponse response = page.pay(
                    payOrder.getSubject(),
                    payOrder.getOrderNo(),
                    payOrder.getAmount().toString(),
                    StringUtils.isEmpty(dto.getCallUrl())?info.getReturnUrl():dto.getCallUrl()//同步回调地址
            );
            System.out.println(response.getBody());

            // 3. 处理响应或异常
            if (ResponseChecker.success(response)) {
                System.out.println("调用成功");
                return response.getBody();
            } else {
                System.err.println("调用失败，原因：");
                throw new GlobalException("支付调用失败");
            }
        } catch (Exception e) {
            System.err.println("调用遭遇异常，原因：" + e.getMessage());
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    private Config getOptions(AlipayInfo info) {
        Config config = new Config();
        config.protocol = info.getProtocol();
        config.gatewayHost = info.getGatewayHost();//沙箱API地址
        config.signType = info.getSignType();
        config.appId = info.getAppId();
        // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
        config.merchantPrivateKey = info.getMerchantPrivateKey();
        //注：如果采用非证书模式，则无需赋值上面的三个证书路径，改为赋值如下的支付宝公钥字符串即可
        config.alipayPublicKey = info.getAlipayPublicKey();
        //可设置异步通知接收服务地址（可选）
        config.notifyUrl = info.getNotifyUrl();
        //可设置AES密钥，调用AES加解密相关接口时需要（可选）
        config.encryptKey = "";
        return config;
    }
}
